#include "StdAfx.h"
#include "RegistryManager.h"
#include "FilterListRegEntry.h"
#include "Exceptions.h"
#include "utils.h"
#include <string>
#include <vector>
#include <utility>

using namespace std;

CRegistryManager::CRegistryManager(void)
	: ADLOCKER_TURNED_ON(1), ADLOCKER_TURNED_OFF(0)
{
}


CRegistryManager::~CRegistryManager(void)
{
}

vector<CFilterListRegEntry> CRegistryManager::GetFilterListsRegEntries()
{
	vector<CFilterListRegEntry> filterLists;

	HKEY regKey = OpenAdBlockerKey(L"Software\\AppDataLow\\IE AdBlocker\\FilterLists");

	filterLists = GetFilterListsRegEntries(regKey);

	RegCloseKey(regKey);

	return filterLists;
}



wstring CRegistryManager::GetInstallationPath()
{	
	HKEY regKey = OpenAdBlockerKey();

	wstring installationPath = GetStringData(regKey, L"Path");

	RegCloseKey(regKey);

	return installationPath;
}

bool CRegistryManager::IsAdblockerTurnedOn()
{
	DWORD isTurnOn = GetIsTurnedOnValue();

	if(isTurnOn == ADLOCKER_TURNED_ON)
		return true;
	else
		return false;
}

void CRegistryManager::TurnAdBlockerOn()
{
	SetIsTurnedOnValue(ADLOCKER_TURNED_ON);
}

void CRegistryManager::TurnAdBlockerOff()
{
	SetIsTurnedOnValue(ADLOCKER_TURNED_OFF);
}
//==========================//
//private functions
HKEY CRegistryManager::OpenAdBlockerKey()
{
	HKEY regKey;	
	HRESULT hr = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\AppDataLow\\IE AdBlocker", 0, KEY_ALL_ACCESS, &regKey);

	if(hr != ERROR_SUCCESS)
		throw NoRegistryKeyException("Software\\AppDataLow\\IE AdBlocker");
	else
		return regKey;
}

HKEY CRegistryManager::OpenAdBlockerKey(wstring keyPath)
{
	HKEY regKey;	
	HRESULT hr = RegOpenKeyEx(HKEY_CURRENT_USER, keyPath.c_str(), 0, KEY_ALL_ACCESS, &regKey);

	if(hr != ERROR_SUCCESS)
		throw NoRegistryKeyException(toStdString(keyPath));
	else
		return regKey;
}

HKEY CRegistryManager::OpenAdBlockerKey(HKEY parentRegKey, LPCWSTR keyPath)
{
	HKEY regKey;	
	HRESULT hr = RegOpenKeyEx(parentRegKey, keyPath, 0, KEY_ALL_ACCESS, &regKey);

	if(hr != ERROR_SUCCESS)
		throw NoRegistryKeyException(toStdString(keyPath));
	else
		return regKey;
}

vector<CFilterListRegEntry> CRegistryManager::GetFilterListsRegEntries(HKEY regKey)
{
	vector<CFilterListRegEntry> filterListRegEntires;

	LONG retCode;
	DWORD numOfSubKeys;
    DWORD maxSubKeyLen;
	retCode = RegQueryInfoKey(regKey, NULL, NULL, NULL, &numOfSubKeys, &maxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
	if( (retCode == ERROR_SUCCESS) && (numOfSubKeys != 0) )
	{

		TCHAR* subKeyName = new TCHAR[maxSubKeyLen+1];	
		for(int i = 0; i < numOfSubKeys; i++)
		{			
			DWORD subKeyNameBufferSize = maxSubKeyLen+1;

			retCode = RegEnumKeyEx(regKey, i, subKeyName, &subKeyNameBufferSize, NULL, NULL, NULL, NULL);
			if(retCode == ERROR_SUCCESS)
			{
				HKEY subRegKey = OpenAdBlockerKey(regKey, subKeyName);

				auto filterListEntry = GetFilterListRegEntry(subRegKey);

				filterListRegEntires.push_back(filterListEntry);

				RegCloseKey(subRegKey);
			}
		}
		delete[] subKeyName;
	}

	return filterListRegEntires;
}

CFilterListRegEntry CRegistryManager::GetFilterListRegEntry(HKEY regKey)
{
	CFilterListRegEntry filterListRegEntry;

	filterListRegEntry.Name = GetStringData(regKey, L"Name");
	filterListRegEntry.Path = GetStringData(regKey, L"Path");
	filterListRegEntry.UrlSubscription = GetStringData(regKey, L"UrlSubscription");

	return filterListRegEntry;
}

void CRegistryManager::SetIsTurnedOnValue(DWORD value)
{	
	HRESULT hr = S_OK;
	
	HKEY regKey = OpenAdBlockerKey();

	hr = RegSetValueEx(regKey, L"IsTurnedOn", 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD));
	if(hr != ERROR_SUCCESS)
		throw NoRegistryValueException("IsTurnedOn");

	RegCloseKey(regKey);
}

DWORD CRegistryManager::GetIsTurnedOnValue()
{	
	HRESULT hr = S_OK;
	
	HKEY regKey = OpenAdBlockerKey();
	
	DWORD value = GetDwordData(regKey, L"IsTurnedOn");

	RegCloseKey(regKey);

	return value;
}

wstring CRegistryManager::GetStringData(HKEY regKey, const wstring& value)
{
	DWORD dataBufferSize;
	HRESULT	hr = RegQueryValueEx(regKey, value.c_str(), 0, 0, NULL, &dataBufferSize);
	
	if(hr != ERROR_SUCCESS)
		throw RegistryException(toStdString(value));

	BYTE* data = new BYTE[dataBufferSize];

	hr = RegQueryValueEx(regKey, value.c_str(), 0, 0, (LPBYTE)data, &dataBufferSize);	

	wstring stringData((TCHAR*)data);
	delete[] data;

	if(hr != ERROR_SUCCESS)
		throw NoRegistryValueException(toStdString(value));

	return stringData;
}

DWORD CRegistryManager::GetDwordData(HKEY regKey, const wstring& value)
{
	DWORD data = 0;
	DWORD cbData = sizeof(data);

	HRESULT hr = RegQueryValueEx(regKey, value.c_str(), 0, 0, (LPBYTE)&data, &cbData);
	if(hr != ERROR_SUCCESS)
		throw NoRegistryValueException(toStdString(value));

	return data;
}